/**
 * Copyright &copy; 2012-2013 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package com.featherlike.feather.generator.impl;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.featherlike.feather.generator.Constant;
import com.featherlike.feather.generator.FreeMarkers;
import com.featherlike.feather.generator.Generator;
import com.featherlike.feather.generator.IGeneratorCfg;
import com.featherlike.feather.generator.entity.Column;
import com.featherlike.feather.generator.entity.Field;
import com.featherlike.feather.generator.entity.Table;
import com.featherlike.feather.generator.excel.ExcelContext;
import com.featherlike.framework.common.util.FileUtil;
import com.featherlike.framework.common.util.MapUtil;
import com.featherlike.framework.common.util.StringUtil;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 代码生成器
 * 
 * @author ThinkGem
 * @version 2013-06-21
 */
public class GeneratorImpl implements Generator {

	public GeneratorCfg generatorCfg = GeneratorCfg.instance();

	private Configuration cfg;

	private GeneratorImpl() {
		cfg = new Configuration();
		// 代码模板配置
		try {
			cfg.setDirectoryForTemplateLoading(new File(generatorCfg
					.getTemplatePath()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static Generator instance;

	public static Generator instance() {
		if (null == instance) {
			instance = new GeneratorImpl();
		}
		return instance;
	}

	private static Logger logger = LoggerFactory.getLogger(GeneratorImpl.class);

	/**
	 * 将内容写入文件
	 * 
	 * @param content
	 * @param filePath
	 */
	public static void writeFile(String content, String filePath) {
		try {
			if (FileUtil.createFile(filePath)) {
				FileWriter fileWriter = new FileWriter(filePath, true);
				BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
				bufferedWriter.write(content);
				bufferedWriter.close();
				fileWriter.close();
			} else {
				logger.info("生成失败，文件已存在！");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private List<Map<String, Object>> getDataMaps(
			Map<Table, List<Column>> tableMap) {
		List<Map<String, Object>> dataMaps = new ArrayList<Map<String, Object>>();

		for (Map.Entry<Table, List<Column>> entry : tableMap.entrySet()) {
			Table table = entry.getKey();
			// 表名
			String tableName = table.getName();
			// 类名-首字母为小写
			String className = StringUtil.toCamelhump(tableName
					.substring(tableName.indexOf("_") + 1));

			List<Column> columnList = entry.getValue();
			List<Field> fieldList = transformFieldList(columnList);
			Map<String, Object> dataMap = MapUtil.newHashMap();

			dataMap.put(Constant.KEY_TABLE, table);
			dataMap.put("columnList", columnList);
			dataMap.put(Constant.KEY_CLASSNAME, className);
			dataMap.put("fieldList", fieldList);
			dataMap.put("StringUtil", new StringUtil());
			dataMap.putAll(generatorCfg.getModel(className));

			dataMaps.add(dataMap);
		}
		return dataMaps;
	}

	/**
	 * @description 生成所有文件
	 * @updated by WYY 2013年11月24日 下午3:41:36
	 * @param tableMap
	 * @throws IOException
	 */
	public void generateAll(Map<Table, List<Column>> tableMap)
			throws IOException {
		List<Map<String, Object>> dataMaps = getDataMaps(tableMap);
		for (Map<String, Object> dataMap : dataMaps) {
			// 生成Entity
			generateJava(dataMap, Constant.ENTITY);
			// 生成DAO
			generateJava(dataMap, Constant.DAO);
			// 生成Service
			generateJava(dataMap, Constant.SERVICE);
			// 生成Controller
			generateJava(dataMap, Constant.CONTROLLER);
			// 生成viewForm
			generateView(dataMap, Constant.VIEW_FORM);
			// 生成viewList
			generateView(dataMap, Constant.View_LIST);
			// 生成sql
			generateSQL(dataMap);
		}
		logger.debug("Generated success...");
	}

	public void generateAllSQL(Map<Table, List<Column>> tableMap)
			throws IOException {
		List<Map<String, Object>> dataMaps = getDataMaps(tableMap);
		for (Map<String, Object> dataMap : dataMaps) {
			generateSQL(dataMap);
		}
	}

	public void generateAllJava(Map<Table, List<Column>> tableMap)
			throws IOException {
		List<Map<String, Object>> dataMaps = getDataMaps(tableMap);
		for (Map<String, Object> dataMap : dataMaps) {
			// 生成Entity
			generateJava(dataMap, Constant.ENTITY);
			// 生成DAO
			generateJava(dataMap, Constant.DAO);
			// 生成Service
			generateJava(dataMap, Constant.SERVICE);
			// 生成Controller
			generateJava(dataMap, Constant.CONTROLLER);
			// 生成viewForm
			generateView(dataMap, Constant.VIEW_FORM);
			// 生成viewList
			generateView(dataMap, Constant.View_LIST);
		}
	}

	private void generateSQL(Map<String, Object> dataMap) throws IOException {
		Template template = cfg.getTemplate(Constant.TABLE
				+ Constant.FTL_SURFIX);
		String content = FreeMarkers.renderTemplate(template, dataMap);
		String filePath = generatorCfg.getSqlPath(((Table) dataMap
				.get(Constant.KEY_TABLE)).getName());
		writeFile(content, filePath);
		logger.info("Table: {}", filePath);
	}

	private void generateJava(Map<String, Object> dataMap, String classType)
			throws IOException {
		Template template = cfg.getTemplate(classType + Constant.FTL_SURFIX);
		String content = FreeMarkers.renderTemplate(template, dataMap);

		String filePath = generatorCfg.getJavaPath(
				(String) dataMap.get(Constant.KEY_CLASSNAME), classType);
		writeFile(content, filePath);
		logger.info("Java: {}", filePath);
	}

	private void generateView(Map<String, Object> dataMap, String viewType)
			throws IOException {
		Template template = cfg.getTemplate(Constant.VIEW + viewType
				+ Constant.FTL_SURFIX);
		String content = FreeMarkers.renderTemplate(template, dataMap);
		String filePath = generatorCfg.getViewPath(
				(String) dataMap.get(Constant.KEY_CLASSNAME), viewType);
		writeFile(content, filePath);
		logger.info("View: {}", filePath);
	}

	private List<Field> transformFieldList(List<Column> columnList) {
		List<Field> fieldList = new ArrayList<Field>(columnList.size());
		for (Column column : columnList) {
			String fieldName = generatorCfg.dbKeyInfo.transformFieldName(column
					.getName());
			String fieldType = generatorCfg.dbKeyInfo.transformFieldType(column
					.getType());
			String fieldComment = column.getComment();
			String fieldLength = column.getLength();
			String listPage = column.getListPage();
			String queryPage = column.getQueryPage();
			String modifyPage = column.getModifyPage();
			String asLink = column.getAsLink();
			String dictType = column.getDictType();
			fieldList.add(new Field(fieldName, fieldType, fieldComment, Integer
					.parseInt(fieldLength), listPage, queryPage, modifyPage,
					asLink, dictType));
		}
		return fieldList;
	}

	public Map<Table, List<Column>> getTableMapFromExcel() {
		return ExcelContext.getInstance().getTableMapFromExcel(
				this.getCfg().getExcelPath());
	}

	@Override
	public IGeneratorCfg getCfg() {
		return generatorCfg;
	}
}
